using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using Microsoft.Data.Schema.Extensibility;
using Microsoft.Data.Schema.SchemaModel;
using Microsoft.Data.Schema.ScriptDom.Sql;
using Microsoft.Data.Schema.Sql.SchemaModel;
using Microsoft.Data.Schema.Sql;
using Microsoft.Data.Schema.StaticCodeAnalysis;
using System.IO;
using System.Text.RegularExpressions;



namespace Neznayka
{
    /// <summary>
    /// This is a SQL rule which returns a warning message 
    /// whenever it finds a variable name that has a single digit numeric suffix.
    /// This is generally bad form!.
    /// </summary>

    [DatabaseSchemaProviderCompatibility(typeof(SqlDatabaseSchemaProvider))]
    [DataRuleAttribute(
        NeznaykaConstants.NameSpace,
        NeznaykaConstants.VariableNameSuffixRuleId,
        NeznaykaConstants.ResourceBaseName,
        NeznaykaConstants.VariableNameSuffix_RuleName,
        NeznaykaConstants.CategoryVariableNaming,
        DescriptionResourceId = NeznaykaConstants.VariableNameSuffix_ProblemDescription)]
    [SupportedElementType(typeof(ISqlFunction))]
    [SupportedElementType(typeof(ISqlTableValuedFunction))]
    [SupportedElementType(typeof(ISqlMultiStatementTableValuedFunction))]
    [SupportedElementType(typeof(ISqlProcedure))]
    [SupportedElementType(typeof(ISqlTrigger))]
    public class VariableNameSuffixRule : StaticCodeAnalysisRule
    {
        #region Overrides
        /// <summary>
        /// Analyze the model element
        /// </summary>
        public override IList<DataRuleProblem> Analyze(DataRuleSetting ruleSetting, DataRuleExecutionContext context)
        {

            // (Re)-Load Environment settings
            List<DataRuleProblem> problems;
            SqlSchemaModel sqlSchemaModel;
            ISqlModelElement sqlElement;
            TSqlFragment sqlFragment;
            DMVRuleSetup.RuleSetup(context, out problems, out sqlSchemaModel, out sqlElement, out sqlFragment);

            // visitor to get the ocurrences of variable declarations
            VariableDefinitionVisitor visitor = new VariableDefinitionVisitor();
            sqlFragment.Accept(visitor);
            List<DeclareVariableElement> variableDeclarations = visitor.VariableDeclarations;

            // Create problems for variable found with a single digit postpended.
            // Allow short names to have digits, there's less likelihood of confusing them
            // and we're restricting them to ints only anyway
            foreach (DeclareVariableElement variableDeclaration in variableDeclarations)
            {
                string varName = variableDeclaration.VariableName.Value;
                if (varName.Length > DMVSettings.MinimumVariableNameLength)
                {
                    Regex _regex = new Regex(@"^@.*\D\d$");

                    Match match = _regex.Match(varName.ToLower());
                    if (match.Success)
                    {
                        DataRuleProblem problem = new DataRuleProblem(this,
                                                    String.Format(CultureInfo.CurrentCulture, this.RuleProperties.Description, SqlRuleUtils.GetElementName(sqlSchemaModel, sqlElement)),
                                                    sqlElement);

                        SqlRuleUtils.UpdateProblemPosition(problem, variableDeclaration.StartOffset, variableDeclaration.FragmentLength);
                        problems.Add(problem);
                    }
                }
            }

            return problems;
        }

        #endregion    
 
    }
}